package p2psvideo;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.Surface;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import p2pproxy.FileTimeInfo;
import p2pproxy.P2PSClient;
import p2pproxy.P2PSManager;
import p2psvideo.Interfaces.OnHttpResponse;
import p2psvideo.aidl.OnBufferingUpdateListener;
import p2psvideo.aidl.OnFileDownloadCreatedListener;
import p2psvideo.aidl.OnFileDownloadFailedListener;
import p2psvideo.aidl.OnFileDownloadFinishedListener;
import p2psvideo.aidl.OnFileDownloadProgressListener;
import p2psvideo.aidl.OnFileListChangedListener;
import p2psvideo.aidl.OnVideoSizeChangedListener;

public class P2PSService extends Service {	
	private P2PSManager _mgr;
	private P2PSClient _client;
	private P2PSMediaPlayer _player;
	private Surface _surface;
	private IP2PSRemote.Stub _intfPlay;
	private BroadcastReceiver _networkChangedReceiver;
	private int _appRefCount = 0;
	private boolean _allowP2P = false;
	private Handler _handler;
	private boolean _isBackground = true;
	private boolean _currentAllowDownload = false;
	static final String TAG="P2PSService";
	protected static final int MSG_PULL_EVENT = 0;
	private boolean _eventPullerStarted = false;
	private OnFileListChangedListener _onFileListChangedListener;
	protected OnVideoSizeChangedListener _onVideoSizeChanged;
	protected OnFileDownloadProgressListener _onFileDownloadProgressListener;
	protected OnBufferingUpdateListener _onBufferUpdate;
	protected OnFileDownloadFinishedListener _onDownloadFinished;
	
	public class P2PSBinder extends Binder
	{
		public P2PSService getService()
		{
			return P2PSService.this;
		}
	}
	
	///判断是否是昂贵的的网络, 非WIFI/以太网都是昂贵网络
	private boolean isExpensiveNetwork()
	{
		 ConnectivityManager cmgr = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);  
		 try {
			 NetworkInfo ninfo = cmgr.getActiveNetworkInfo();  
			 if (ninfo == null) return false;
			 int type = ninfo.getType();
			 if (type != ConnectivityManager.TYPE_ETHERNET && type != ConnectivityManager.TYPE_WIFI) return true;
			 else return false;
		 } catch(Exception e) {
			 e.printStackTrace();
		 }
		 return false;
	}
	
	///保存root到配置
	private void saveCacheRoot(String root, boolean add)
	{
		SharedPreferences prop = getSharedPreferences("P2PSService", Context.MODE_PRIVATE);
		Set<String> cacheRoots = prop.getStringSet("cache_root", null);		
		if (cacheRoots == null) {
			cacheRoots = new TreeSet<String>();
		}
		if (add) {
			cacheRoots.add(root);
		} else {
			cacheRoots.remove(root);
		}
		Editor edtor = prop.edit();
		edtor.putStringSet("cache_root", cacheRoots);
		edtor.commit();
	}
	
	private void _startPullEvents()
	{
		if (_eventPullerStarted) return;
		_eventPullerStarted = true;
		_handler.removeMessages(MSG_PULL_EVENT);
		_handler.sendEmptyMessage(MSG_PULL_EVENT);
		_mgr.enableEventsQueue(true);
	}
	
	private void _stopPullEvents()
	{
		_eventPullerStarted = false;
		_handler.removeMessages(MSG_PULL_EVENT);
		_mgr.enableEventsQueue(false);
	}
	
	protected void _pullEvents() {
		synchronized(this) {
			P2PSManager.P2PSMgrEventInfo info = new P2PSManager.P2PSMgrEventInfo(); 
			while (_mgr.pullEvent(info)) {
				_handleEvents(info);
			}
			if (_eventPullerStarted) {
				_handler.sendEmptyMessageDelayed(MSG_PULL_EVENT, 500);
			}
		}
	}
	
	private void _handleEvents(P2PSManager.P2PSMgrEventInfo info) 
	{
		switch(info.eventCode)
		{
		case P2PSManager.evFileListChanged:
			if (_onFileListChangedListener != null) {
				try {
					_onFileListChangedListener.onChanged(info.vsid);
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
		break;
		case P2PSManager.evFileCreateDownloadOK:
		case P2PSManager.evFileCreateDownloadFailed:
			_handleDownloadEvents(info);
		break;
		case P2PSManager.evFileDownloadProgress:
			if (_onFileDownloadProgressListener != null) {
				String fileInfo = _mgr.getFileInfo(info.vsid);
				if (fileInfo != null && !fileInfo.equals("")) {
					try {
						JSONObject cfg = new JSONObject(fileInfo);
						_onFileDownloadProgressListener.onProgress(info.vsid, cfg.getInt("percent"));
					} catch(Throwable e) {
						e.printStackTrace();
					}
				}				
			}
		break;
		case P2PSManager.evFileDownloadFinished:
			if (_onDownloadFinished != null) {
				try {
					_onDownloadFinished.onDownloadFinished(info.vsid);
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
		}		
	}
	
	private void _handleDownloadEvents(P2PSManager.P2PSMgrEventInfo info)
	{
		if (info.eventId == null || info.eventId.equals("")) return;
		DownloadItem it = _downloadCallbacks.get(info.eventId);
		if (it == null) return;
		_downloadCallbacks.remove(info.eventId);
		try {
			if (it.onCreate != null && info.eventCode == P2PSManager.evFileCreateDownloadOK) {
				it.onCreate.onCreated(info.vsid);
			}
			if (it.onFailed != null && info.eventCode == P2PSManager.evFileCreateDownloadFailed) {
				it.onFailed.onFailed(info.vsid);
			}
		} catch(Throwable e) {
			e.printStackTrace();
		}
	}
	
	private void _handleVideoSize() {
		synchronized(this) {
			if (_player == null) return;
			if (_onVideoSizeChanged != null) {
				try {
					_onVideoSizeChanged.onVideoSizeChanged(_player.getWidth(), _player.getHeight());
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}			
		}
	}
	
	private void _handleBufferUpdate(int percent)
	{
		synchronized(this) {
			if (_player == null) return;
			if (_onBufferUpdate != null) {
				try {
					if (percent > 100) percent = 100;
					Log.v("P2PSService", "Buffering: " + percent);
					_onBufferUpdate.onBufferingUpdate(percent);
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}			
		}
	}
	
	@Override
	public void onCreate() {
		super.onCreate();		
		_handler = new Handler() {

			@Override
			public void handleMessage(Message msg) {
				if (msg.what == MSG_PULL_EVENT) {
					_pullEvents();
				} else if (msg.what == 100) { //P2PSMediaPlayer.MSG_VIDEO_SIZE
					_handleVideoSize();
				} else if (msg.what == 101) { //P2PSMediaPlayer.MSG_BUFFER_UPDATE
					_handleBufferUpdate(msg.arg1);
				} else if (msg.what == 103) { //P2PSMediaPlayer.MSG_BUFFER_FINISH
					_handleBufferUpdate(100);
				}
			}			
		};
		//监视网络变化, 如果没有廉价网络禁用p2p
		_networkChangedReceiver = new BroadcastReceiver() {
	        @Override
	        public void onReceive(Context context, Intent intent) {
	            String action = intent.getAction();
	            if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
		            synchronized(P2PSService.this) {
		            	updateAllowDownload();
		            	if (_mgr == null) return;
						_mgr.setAllowP2P(_allowP2P && !P2PSService.this.isExpensiveNetwork());
		            }	     
	            }
	        }
	    };
	    IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);  
	    this.registerReceiver(_networkChangedReceiver, filter);  
		
		SharedPreferences prop = getSharedPreferences("P2PSService", Context.MODE_PRIVATE);
		Set<String> cacheRoots = prop.getStringSet("cache_root", null);
		_allowP2P = prop.getBoolean("allow_p2p", true);
		Log.v("P2PSService", "Service creating");
		_mgr = new P2PSManager();
		JSONObject opts = new JSONObject();
		if (cacheRoots != null && cacheRoots.size() != 0) {	//缓存目录配置	
			String roots=null;			
			Iterator<String> i=cacheRoots.iterator();
			while(i.hasNext()) {
				if (roots == null) {
					roots = i.next();
				} else {
					roots += "|"+i.next();
				}				
			}			
			try {
				opts.put("cache_root", roots);
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		try {
			opts.put("max_p2p_pull_requests", prop.getInt("max_p2p_pull_requests", 256));
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			opts.put("max_p2p_files", prop.getInt("max_p2p_files", 32));
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		try {
			opts.put("allow_p2p", _allowP2P && !isExpensiveNetwork());
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		JSONObject proxy = new JSONObject();		
		try {
			proxy.put("enable", true);
			opts.put("proxy", proxy);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		_mgr.open(opts.toString());		
		_intfPlay = new IP2PSRemote.Stub() {						
			@Override
			public boolean beginPlay(String type) throws RemoteException {
				return P2PSService.this.beginPlay(type);
			}

			@Override
			public boolean addFile(String urls, String streamers, String opts,
					int start, int duration, int index, int format)
					throws RemoteException {
				return P2PSService.this.addFile(urls, streamers, opts, start, duration, index, format);
			}

			@Override
			public boolean stopped() throws RemoteException {
				return P2PSService.this.stopped();
			}

			@Override
			public String getStatus() throws RemoteException {
				return P2PSService.this.getStatus();
			}

			
			@Override
			public boolean seek(int t) throws RemoteException {
				return P2PSService.this.seek(t);
			}

			@Override
			public boolean seekToKeyFrame(int t) throws RemoteException {
				return P2PSService.this.seekToKeyFrame(t);
			}

			@Override
			public boolean seekByTimeCode(double tc, boolean keyFrameAcuracy, boolean mustMatch, boolean asc) throws RemoteException {
				return P2PSService.this.seekByTimeCode(tc, keyFrameAcuracy, mustMatch, asc);
			}

			@Override
			public FileTimeInfo getFileTimeInfo(int idx) throws RemoteException {
				return P2PSService.this.getFileTimeInfo(idx);
			}

			@Override
			public boolean isLive() throws RemoteException {
				return P2PSService.this.isLive();
			}

			@Override
			public void pause() throws RemoteException {
				P2PSService.this.pause();				
			}

			@Override
			public void play() throws RemoteException {
				P2PSService.this.play();
			}

			@Override
			public int duration() throws RemoteException {
				return P2PSService.this.duration();
			}

			@Override
			public boolean ready() throws RemoteException {
				return P2PSService.this.ready();
			}

			@Override
			public boolean error() throws RemoteException {
				return P2PSService.this.error();
			}
			
			@Override
			public int port() throws RemoteException {
				return P2PSService.this.port();
			}

			@Override
			public boolean noSignal() throws RemoteException {
				return P2PSService.this.noSignal();
			}	
			@Override
			public double getOutSidePlayerTimeCode(int outsideTime) throws RemoteException {
				return P2PSService.this.getOutSidePlayerTimeCode(outsideTime);
			}	
			@Override
			public int getOutSidePlayerStreamTime(int outsideTime) throws RemoteException {
				return P2PSService.this.getOutSidePlayerStreamTime(outsideTime);
			}

			@Override
			public int inTimeShiftMode() throws RemoteException {
				return P2PSService.this.inTimeShiftMode();
			}
		

			@Override
			public boolean removeFile(int index) throws RemoteException {
				return P2PSService.this.removeFile(index);
			}

			@Override
			public void clear() throws RemoteException {
				P2PSService.this.clear();
			}

			@Override
			public int fileCount() throws RemoteException {
				return P2PSService.this.fileCount();
			}

			@Override
			public boolean fileReady(int index) throws RemoteException {
				return P2PSService.this.fileReady(index);
			}
			
			@Override
			public void endPlay() throws RemoteException {
				P2PSService.this.endPlay();
			}

			@Override
			public boolean bufferring() throws RemoteException {
				
				return P2PSService.this.bufferring();
			}

			@Override
			public boolean usingRaw() throws RemoteException {				
				return P2PSService.this.usingRaw();
			}

			@Override
			public void setSurface(Surface surface) throws RemoteException {
				P2PSService.this.setSurface(surface);
			}

			@Override
			public boolean isEof() throws RemoteException {
				return P2PSService.this.isEof();
			}

			@Override
			public int getRawTime() throws RemoteException {
				return P2PSService.this.getRawTime();
			}

			@Override
			public boolean rawBufferring() throws RemoteException {
				return P2PSService.this.rawBufferring();
			}

			@Override
			public long getRawBufferLength() throws RemoteException {
				return P2PSService.this.getRawBufferLength();
			}

			@Override
			public String getSupportedVideoCodecList() throws RemoteException {
				return P2PSService.this.getSupportedVideoCodecList();
			}
			
			///////////////////////////////////////////////////////////////////////////
			
			@Override
			public void setMaxDownload(int maxDownloads) throws RemoteException {
				P2PSService.this.setMaxDownload(maxDownloads);
			}
			
			@Override
			public boolean setDownloadType(String vsid, int type, boolean downloadImd)
					throws RemoteException {
				return P2PSService.this.setDownloadType(vsid, type, downloadImd);
			}
			
			@Override
			public void setAllowP2P(boolean allow) throws RemoteException {
				P2PSService.this.setAllowP2P(allow);	
			}

			@Override
			public boolean getAllowP2P() throws RemoteException {
				return P2PSService.this.getAllowP2P();
			}

			@Override
			public boolean removeFileByID(String vsid) throws RemoteException {
				return P2PSService.this.removeFileByID(vsid);
			}
			
			@Override
			public boolean removeCacheRoot(String root, boolean removeVideo)
					throws RemoteException {
				return P2PSService.this.removeCacheRoot(root, removeVideo);
			}
			
			@Override
			public int getMaxDownloads() throws RemoteException {
				return P2PSService.this.getMaxDownloads();
			}
			
			@Override
			public String getFiles() throws RemoteException {
				return P2PSService.this.getFiles();
			}
			
			@Override
			public String getFileInfo(String vsid) throws RemoteException {
				return P2PSService.this.getFileInfo(vsid);
			}
			
			@Override
			public String getCacheRoots() throws RemoteException {
				return P2PSService.this.getCacheRoots();
			}
			
			@Override
			public boolean existsFile(String vsid) throws RemoteException {
				return P2PSService.this.existsFile(vsid);
			}
			
			@Override
			public boolean createDownload(String urls, String streamers, String opts,
					int type, int format, OnFileDownloadCreatedListener onCreate, OnFileDownloadFailedListener onFailed) throws RemoteException {
				return P2PSService.this.createDownload(urls, streamers, opts, type, format, onCreate, onFailed);
			}
			
			@Override
			public boolean cacheSpaceTooSmall() throws RemoteException {
				return P2PSService.this.cacheSpaceTooSmall();
			}
			
			@Override
			public void allowDownload(int allow, boolean background) throws RemoteException {
				P2PSService.this.allowDownload(allow, background);
			}
			
			@Override
			public boolean addCacheRoot(String root, boolean resetP2P)
					throws RemoteException {
				return P2PSService.this.addCacheRoot(root, resetP2P);
			}

			@Override
			public boolean enableLocalStorage(boolean enable, boolean inAppStorage) throws RemoteException {
				return P2PSService.this.enableLocalStorage(enable, inAppStorage);
			}

			@Override
			public int getAllowDownload() throws RemoteException {
				return P2PSService.this.getAllowDownload();
			}

			@Override
			public boolean getAllowDownloadBackground() throws RemoteException {
				return P2PSService.this.getAllowDownloadBackground();
			}

			@Override
			public void setBackground(boolean back) throws RemoteException {
				P2PSService.this.setBackground(back);
			}

			@Override
			public void setOnVideoSizeChangedListener(
					OnVideoSizeChangedListener l) throws RemoteException {
				synchronized(P2PSService.this) {
					_onVideoSizeChanged = l;
				}
			}

			@Override
			public void setOnFileListChangedListener(OnFileListChangedListener l)
					throws RemoteException {
				synchronized(P2PSService.this) {
					_onFileListChangedListener = l;
				}
			}

			@Override
			public void setOnFileDownloadProgressListener(
					OnFileDownloadProgressListener l) throws RemoteException {
				synchronized(P2PSService.this) {
					_onFileDownloadProgressListener = l;
				}
			}
						

			@Override
			public void startPullEvents() throws RemoteException {
				synchronized(P2PSService.this) {
					_startPullEvents();
				}
			}

			@Override
			public void stopPullEvents() throws RemoteException {
				synchronized(P2PSService.this) {
					_stopPullEvents();
				}
			}

			@Override
			public void setOnBufferingUpdateListener(
					OnBufferingUpdateListener l) throws RemoteException {
				synchronized(P2PSService.this) {
					_onBufferUpdate = l;
				}
			}

			@Override
			public void setOnFileDownloadFinishedListener(
					OnFileDownloadFinishedListener l) throws RemoteException {
				_onDownloadFinished = l;
			}

			@Override
			public String getCurrentPlayVsid() throws RemoteException {
				synchronized(P2PSService.this) {
					if (_client == null) return null;
					return _client.getCurrentPlayVsid();
				}
			}

			@Override
			public boolean isCurrentAllowDownload() throws RemoteException {
				return _currentAllowDownload;
			}
			

			@Override
			public void readHttpRtmfpFile(String httpUrls, String rtmfpUrls,
					String filePath, final p2psvideo.aidl.OnHttpResponse cb)
					throws RemoteException {
				synchronized(P2PSService.this) {
					if (_mgr == null) {
						cb.onData(true, false, null);
						return;
					}
					_mgr.readHttpRtmfpFile(httpUrls, rtmfpUrls, filePath, new OnHttpResponse() {

						@Override
						public void onData(boolean error, boolean rtmfpget,
								byte[] data) {
							try {
								cb.onData(error, rtmfpget, data);
							} catch (RemoteException e) {								
								e.printStackTrace();
							}
						}
						
					});
				}
				
			}

			@Override
			public int getProxyPort() throws RemoteException {
				synchronized(P2PSService.this) {
					if (_mgr == null) return 0;
					else return _mgr.getProxyPort();
				}
			}
		};
		updateAllowDownload();
						
		Log.v("P2PSService", "Service creation is done");
	}

	private boolean seekToKeyFrame(int t) {
		synchronized(this) {
			if (_client == null) return false;
			if (_client.seekToKeyFrame(t)) {
				if (_player != null) { //restart
					_player.start();
				}
				return true;
			} else return false;
		}
	}

	private boolean seekByTimeCode(double tc, boolean keyFrameAcuracy, boolean mustMatch, boolean asc)
	{
		synchronized(this) {
			if (_client == null) return false;
			if (_client.seekByTimeCode(tc, keyFrameAcuracy, mustMatch, asc)) {
				if (_player != null) { //restart
					_player.start();
				}
				return true;
			} else return false;
		}
	}

	private FileTimeInfo getFileTimeInfo(int idx)
	{
		synchronized(this) {
			if (_client == null) return null;
			FileTimeInfo info = new FileTimeInfo();
			if (!_client.getFileTimeInfo(idx, info)) return null;
			return info;
		}
	}

	protected void setBackground(boolean back) {
		synchronized(this) {
			_isBackground = back;
			updateAllowDownload();
		}
		
	}

	protected boolean getAllowDownloadBackground() {
		synchronized(this) {
			SharedPreferences prop = getSharedPreferences("P2PSService", Context.MODE_PRIVATE);
			return prop.getBoolean("allow_download_background", true);
		}		
	}

	protected int getAllowDownload() {
		synchronized(this) {
			SharedPreferences prop = getSharedPreferences("P2PSService", Context.MODE_PRIVATE);
			return prop.getInt("allow_download", 2);
		}		
	}
	
	protected void saveAllowDownload(int allow, boolean background)
	{
		synchronized(this) {
			SharedPreferences prop = getSharedPreferences("P2PSService", Context.MODE_PRIVATE);
			Editor edtor = prop.edit();			
			edtor.putInt("allow_download", allow);
			edtor.putBoolean("allow_download_background", background);
			edtor.commit();
		}		
	}
	
	protected void updateAllowDownload()
	{
		synchronized(this) {
			int allow = getAllowDownload();
			boolean background = getAllowDownloadBackground();
			boolean result = true;
			if (allow == 0) {
				result = false;
			}
			if (!background && (_appRefCount == 0 || _isBackground) ) {
				result = false;
			}
			if (allow == 1 && isExpensiveNetwork()) {
				result = false;
			}
			_currentAllowDownload = result;
			if (_mgr != null) {
				_mgr.allowDownload(result);
			}
		}
	}

	///获取内置存储缓存路径
	private String getInnerCachePath(){  
        File sdDir = null;
        try {
        	boolean sdCardExist = Environment.getExternalStorageState()    
                              .equals(Environment.MEDIA_MOUNTED);  //判断sd卡是否存在
        	if  (sdCardExist)    
        	{                                   
        		sdDir = Environment.getExternalStorageDirectory();//获取跟目录          		
        		return sdDir.toString() + "/" + getAppName() + "/download";
        	} else return null;
        } catch(Throwable e) {
        	e.printStackTrace();
        	return null;
        }          
    }

	///获取应用内缓存文件夹
	private String getAppCachePath()
	{
		return getApplicationInfo().dataDir + "/p2psdownload";
	}
	
	private static String readFileAsString(String fileName)
	{

	    String str="";

	    File file=new File(fileName);
	    FileInputStream in=null;

	    try {

	        in =new FileInputStream(file);

	        byte[] buffer=new byte[65536];
	        int r = in.read(buffer);
	        if (r <= 0) return str;	        	     
	        str=new String(buffer, 0, r, "UTF-8");

	    } catch (IOException e) {
	    	;

	    } finally {
	    	if (in != null) {
	    		try {
					in.close();
				} catch (IOException e) {					
					e.printStackTrace();
				}
	    	}
	    }
	    return str;
	}
	
	///获取外置存储缓存路径
	private List<String> getExtCachePath(){  	       
	       try {
	    	   String r = readFileAsString("/proc/mounts");
	    	   if (r == null || r.equals("")) return null;
	    	   String[] lines = r.split("\\n");
	    	   if (lines == null || lines.length == 0) return null;
	    	   List<String> res = null;
	    	   for(int i=0; i<lines.length; ++i) {
	    		   if (lines[i] == null) continue;
	    		   String line = lines[i].trim();
	    		   if (line.equals("")) continue;
	    		   String[] parts = line.split(" ");
	    		   if (parts == null) continue;
	    		   if (parts.length < 3) continue;
	    		   if (!parts[2].equals("vfat")) continue;
	    		   if (res == null) {
	    			   res = new LinkedList<String>();
	    		   }
	    		   res.add(parts[1] + "/" + getAppName() + "/download");
	    	   }
	    	   return res;
	        } catch(Throwable e) {
	        	e.printStackTrace();
	        	return null;
	        }          
	  }  
		
	
	private String getAppName()
	{
		return this.getApplication().getPackageName();
	}
	
	protected boolean enableLocalStorage(boolean enable, boolean inAppStorage) {
		synchronized(this) {
			if (_mgr == null) return false;
			boolean everOK = false;
			List<String> extRoots = null;
			if (!inAppStorage) extRoots = getExtCachePath();
			if (extRoots != null) {
				for(int i=0; i<extRoots.size(); ++i) {					
					String extRoot = extRoots.get(i);
					Log.v("P2PSService", "Using SD card root: " + extRoot);
					try {
						File f = new File(extRoot);
						if (!f.exists()) {
							f.mkdirs();
							f = new File(extRoot);
						} 
						if (f.isDirectory()) {
							if (enable) {
								if (_mgr.addCacheRoot(extRoot, true)) {
									saveCacheRoot(extRoot, true);
									everOK = true;
								} 
							} else {
								if (_mgr.removeCacheRoot(extRoot, false)) {
									saveCacheRoot(extRoot, false);
									everOK = true;
								}
							}
						}					
					} catch(Throwable e) {
						e.printStackTrace();
					}	
				}
			}
			
			String userRoot = null;
			if (inAppStorage) {
				userRoot = getAppCachePath();
			} else {
				userRoot = getInnerCachePath();
			}
			if (userRoot != null) {
				Log.v("P2PSService", "Using user cache root: " + userRoot);
				try {
					File f = new File(userRoot);
					if (!f.exists()) {
						f.mkdirs();
						f = new File(userRoot);
					} 
					if (f.isDirectory()) {
						if (enable) {
							if (_mgr.addCacheRoot(userRoot, true)) {
								saveCacheRoot(userRoot, true);
								everOK = true;
							}
						} else {
							if (_mgr.removeCacheRoot(userRoot, false)) {
								saveCacheRoot(userRoot, false);
								everOK = true;
							}
						}
					}					
				} catch(Throwable e) {
					e.printStackTrace();
				}				
			}
			return everOK;
		}
	}

	/*!
	 * @brief 设置允许下载的方式
	 * @param allow 允许方式
	 * 		- 0  不允许下载
	 * 		- 1 仅在WIFI条件下下载
	 * 		- 2 无论如何都下载
	 * @param background 是否允许后台下载
	 */
	protected void allowDownload(int allow, boolean background) {
		synchronized(this) {			
			saveAllowDownload(allow, background);
			updateAllowDownload();
		}
	}
	
	///下载回调
	static class DownloadItem
	{
		OnFileDownloadCreatedListener onCreate;
		OnFileDownloadFailedListener onFailed;
	}
	Map<String, DownloadItem> _downloadCallbacks = new HashMap<String, DownloadItem>();

	protected boolean createDownload(String urls, String streamers,
									 String opts, int type, int format, OnFileDownloadCreatedListener onCreate, final OnFileDownloadFailedListener onFailed) {
		synchronized(this) {
			if (_mgr == null) {
				if (onFailed != null) {
					_handler.post(new Runnable() {
						@Override
						public void run() {
							try {
								onFailed.onFailed("");
							} catch (RemoteException e) {
								e.printStackTrace();
							}
						}						
					});
				}
				return false;
			}
			
			if (!_mgr.createDownload(urls, streamers, opts, type, format)) {
				if (onFailed != null) {
					_handler.post(new Runnable() {
						@Override
						public void run() {
							try {
								onFailed.onFailed("");
							} catch (RemoteException e) {
								e.printStackTrace();
							}
						}						
					});
				}
				return false;
			}
			if (opts != null && !opts.equals("")) {
				try {
					JSONObject cfg = new JSONObject(opts);
					String event_id = cfg.getString("event_id");
					if (event_id != null && !event_id.equals("")) {
						DownloadItem it = new DownloadItem();
						it.onCreate = onCreate;
						it.onFailed = onFailed;
						_downloadCallbacks.put(event_id, it);
					}
				} catch(Throwable e) {
					e.printStackTrace();
				}
			}
			return true;
		}
	}

	protected String getFileInfo(String vsid) {
		synchronized(this) {
			if (_mgr == null) return null;
			return _mgr.getFileInfo(vsid);
		}
	}

	protected int getMaxDownloads() {
		synchronized(this) {
			if (_mgr == null) return 0;
			return _mgr.getMaxDownloads();
		}
	}

	protected boolean setDownloadType(String vsid, int type, boolean downloadImd) {
		synchronized(this) {
			if (_mgr == null) return false;
			return _mgr.setDownloadType(vsid, type, downloadImd, "");
		}
	}

	protected void setMaxDownload(int maxDownloads) {
		synchronized(this) {
			if (_mgr == null) return;
			_mgr.setMaxDownload(maxDownloads);
		}
	}

	protected String getSupportedVideoCodecList() {
		try {
			return P2PSMediaPlayer.getSupportedVideoCodecList(true);
		} catch(Exception e) {
			;
		} catch(Error e) {
			;
		}
		return "";
	}

	protected long getRawBufferLength() {
		synchronized(this) {
			if (_client == null) return 0;
			if (_player == null) return 0;
			return _player.getBufferLength();
		}
	}

	protected boolean rawBufferring() {
		synchronized(this) {
			if (_client == null) return false;
			if (_player == null) return false;
			return _player.bufferring();
		}
	}

	protected int getRawTime() {
		synchronized(this) {
			if (_client == null) return -1;
			if (_player != null) return (int)(_player.getTime()/1000); 
			return -1;
		}
	}

	protected boolean isEof() {
		synchronized(this) {
			if (_client == null) return true;
			if (_player != null) return _player.eof(); 
			return _client.stopped();
		}
	}

	protected void setSurface(Surface surface) {
		synchronized(this) {
			_surface = surface;
			if (_player != null) {
				_player.setSurface(_surface);
			}
		}
	}

	protected boolean usingRaw() {
		synchronized(this) {
			return _player != null;
		}
	}

	protected boolean bufferring() {
		synchronized(this) {
			if (_client == null) {
				Log.d(TAG, "bufferring no _client");
				return false;
			}
			return _client.bufferring();
		}
	}

	///p2p管理器函数
	protected boolean cacheSpaceTooSmall() {
		synchronized(this) {
			if (_mgr == null) return false;
			return _mgr.cacheSpaceTooSmall();
		}
	}

	protected boolean addCacheRoot(String root, boolean resetP2P) {
		synchronized(this) {
			if (_mgr == null) return false;
			if (_mgr.addCacheRoot(root, resetP2P)) {
				saveCacheRoot(root, true);
				return true;
			} else return false;
		}
	}

	protected boolean removeCacheRoot(String root, boolean removeVideo) {
		synchronized(this) {
			if (_mgr == null) return false;
			if (_mgr.removeCacheRoot(root, removeVideo)) {
				saveCacheRoot(root, false);
				return true;
			} else return false;
		}
	}

	protected String getCacheRoots() {
		synchronized(this) {
			if (_mgr == null) return null;
			return _mgr.getCacheRoots();
		}
	}

	protected String getFiles() {
		synchronized(this) {
			if (_mgr == null) return null;
			return _mgr.getFiles();
		}
	}

	protected boolean removeFileByID(String vsid) {
		synchronized(this) {
			if (_mgr == null) return false;
			return _mgr.removeFile(vsid);
		}
	}

	protected boolean existsFile(String vsid) {
		synchronized(this) {
			if (_mgr == null) return false;
			return _mgr.existsFile(vsid);
		}
	}

	protected void setAllowP2P(boolean allow) {
		synchronized(this) {
			SharedPreferences prop = getSharedPreferences("P2PSService", Context.MODE_PRIVATE);
			prop.edit().putBoolean("allow_p2p", allow).commit();
			_allowP2P = allow;
			if (_mgr == null) return;
			_mgr.setAllowP2P(allow && !isExpensiveNetwork());
		}
	}

	protected boolean getAllowP2P()
	{
		return _allowP2P;
	}
	
	///播放函数
	
	protected boolean beginPlay(String type) {
		synchronized(this) {
			if (_client != null) {
				Log.d(TAG, "_client is there");
				return false;
			}
			if (_mgr == null) {
				Log.d(TAG, "_mgr is not created");
				return false;
			}
			_client = new P2PSClient();
			if (type != null) {
				if (type.equals("raw")) {
					if (android.os.Build.VERSION.SDK_INT < 16) {
						type = null;
					}
				} else if (type.equals("tsserver")) {
					;
				} else {
					type = null;
				}
			}
			if (type == null || type.equals("")) {
				if (android.os.Build.VERSION.SDK_INT >= 16) {
					type = "raw";
				} else {
					type = "tsserver";
				}
			} 			
			if (!_client.open(this, _mgr, type)) {
				Log.d(TAG, "_client.open failed");
				_client.close();
				_client = null;
				return false;
			}
			if (_player != null) {
				_player.stop();
				_player = null;
			}
			if (type.equals("raw")) {
				_player = new P2PSMediaPlayer(this.getApplicationContext(), _client, _surface, _handler);
			}
			Log.d(TAG, "beginPlay ok");
			return true;
		}
	}
	
	protected void endPlay() {
		synchronized(this) {
			if (_client == null) {
				Log.d(TAG, "endPlay no _client");
				return;
			}
			if (_player != null) {
				_player.stop();
				_player = null;
			}
			_client.close();
			_client.freeAllDataItems();
			_client = null;
			Log.d(TAG, "endPlay OK");
		}
	}


	protected int getOutSidePlayerStreamTime(int outsideTime) {
		synchronized(this) {
			if (_client == null) return 0;
			return _client.getOutSidePlayerStreamTime(outsideTime);
		}
	}

	protected double getOutSidePlayerTimeCode(int outsideTime) {
		synchronized(this) {
			if (_client == null) return 0;
			return _client.getOutSidePlayerTimeCode(outsideTime);
		}
	}

	protected int port() {
		synchronized(this) {
			if (_client == null) return 0;
			return _client.port();
		}
	}

	protected boolean ready() {
		synchronized(this) {
			if (_client == null) return false;
			return _client.ready();
		}
	}

	protected String getStatus() {
		synchronized(this) {
			if (_client == null) return null;
			return _client.getStatus();
		}
	}

	protected boolean stopped() {
		synchronized(this) {
			if (_client == null) return true;	
			if (_player != null) {
				return _player.eof();
			} else {
				return _client.stopped();
			}
		}
	}

	protected boolean addFile(String urls, String streamers, String opts,
			int start, int duration, int index, int format) {
		synchronized(this) {
			if (_client == null) {
				Log.d(TAG, "addFile no _client");
				return false;
			}
			Log.d(TAG, "addFile: " + urls);
			return _client.addFile(urls, streamers,  opts, start, duration, index, format);
		}
	}
	

    protected boolean fileReady(int index) {
    	synchronized(this) {
    		if (_client == null) return false;
    		return _client.fileReady(index);
    	}
	}


	protected int fileCount() {
		synchronized(this) {
			if (_client == null) return 0;
			return _client.fileCount();
		}
	}


	protected void clear() {
		synchronized(this) {
			if (_client == null) {
				Log.d(TAG, "clear no _client");
				return;
			}
			_client.clear();
			Log.d(TAG, "clear OK");
		}
	}


	protected boolean removeFile(int index) {
		synchronized(this) {
			if (_client == null) return false;
			return _client.removeFile(index);
		}
	}


	protected int inTimeShiftMode() {
		synchronized(this) {
			if (_client == null) return 0;
			return _client.inTimeShiftMode();
		}
	}


	protected boolean noSignal() {
		synchronized(this) {
			if (_client == null) return true;
			return _client.noSignal();
		}
	}


	protected boolean error() {
		synchronized(this) {
			if (_client == null) return false;
			return _client.error();
		}
	}


	protected int duration() {
		synchronized(this) {
			if (_client == null) return 0;
			return _client.duration();
		}
	}


	protected void play() {
		synchronized(this) {
			if (_client == null) return;
			_client.play();
			if (_player != null) {
				_player.resume();
			}
		}
	}


	protected void pause() {
		synchronized(this) {
			if (_client == null) return;
			_client.pause();
			if (_player != null) {
				_player.pause();
			}
		}
	}


	protected boolean isLive() {
		synchronized(this) {
			if (_client == null) return false;
			return _client.isLive();
		}
	}


	protected boolean seek(int t) {
		synchronized(this) {
			if (_client == null) return false;
			boolean r = _client.seek(t);
			if (r) {
				if (_player != null) { //restart
					_player.start();
				}
			}
			return r;
		}
	}
	

	@Override
	public void onDestroy() {
		Log.v("P2PSService", "Service is destroying");
		synchronized(this) {
			_stopPullEvents();
			if (_player != null) {
				_player.stop();
				_player = null;
			} 
			if (_client != null) {
				_client.close();
				_client = null;
			}
			if (_mgr != null) {
				_mgr.close();
				_mgr = null;
			}
		}
		unregisterReceiver(_networkChangedReceiver);
		Log.v("P2PSService", "Service destroy");
		super.onDestroy();
	}

	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		Log.v("P2PSService", "Service bind");		
		synchronized(this) {
			_appRefCount++;
			_startPullEvents();
		}
		return _intfPlay;
	}

	@Override
	public boolean onUnbind(Intent intent) {		
		Log.v("P2PSService", "Service unbind");
		synchronized(this) {
			_appRefCount--;
			if (_appRefCount == 0) {
				_isBackground = true;
				_stopPullEvents();
			}
			updateAllowDownload();	
			_onVideoSizeChanged = null;
			_onFileListChangedListener = null;
			_onFileDownloadProgressListener = null;
			_onBufferUpdate = null;
			_onDownloadFinished = null;
			_downloadCallbacks.clear();
		}
		endPlay();				
		return super.onUnbind(intent);
	}		
	
}
